package com.jnevision.salary.controller;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.api.ApiController;
import com.baomidou.mybatisplus.extension.api.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.jnevision.common.CommonQuery;
import com.jnevision.dept.model.Dept;
import com.jnevision.dept.service.DeptServiceImpl;
import com.jnevision.deptcollect.model.DeptCollect;
import com.jnevision.dict.service.DictServiceImpl;
import com.jnevision.extra.service.ExtraServiceImpl;
import com.jnevision.insurancerate.model.InsuranceRate;
import com.jnevision.insurancerate.service.InsuranceRateServiceImpl;
import com.jnevision.leaveapprovalrecords.service.LeaveApprovalRecordsServiceImpl;
import com.jnevision.overtimeapproval.service.OvertimeApprovalRecordsServiceImpl;
import com.jnevision.replacecardapprovalrecords.service.ReplaceCardApprovalRecordsServiceImpl;
import com.jnevision.salary.model.Salary;
import com.jnevision.salary.model.SalaryVO;
import com.jnevision.salary.service.SalaryServiceImpl;
import com.jnevision.salaryrecord.model.SalaryRecord;
import com.jnevision.salaryrecord.service.SalaryRecordServiceImpl;
import com.jnevision.user.model.User;
import com.jnevision.user.service.UserServiceImpl;
import com.jnevision.userdept.model.UserDept;
import com.jnevision.userdept.service.UserDeptServiceImpl;
import com.jnevision.util.DateUtil;

/**
 * <p>
 * 薪资信息 前端控制器
 * </p>
 *
 * @author gavin
 * @since 2019-07-13
 */
@RestController
@RequestMapping("/salarys")
public class SalaryController extends ApiController {
    @Autowired
    private SalaryServiceImpl salaryServiceImpl;

    @Autowired
    private InsuranceRateServiceImpl insuranceRateServiceImpl;

    @Autowired
    private UserDeptServiceImpl userDeptServiceImpl;

    @Autowired
    private DeptServiceImpl deptServiceImpl;

    @Autowired
    private UserServiceImpl userServiceImpl;
    @Autowired
    private SalaryRecordServiceImpl salaryRecordServiceImpl;
    @Autowired
    private LeaveApprovalRecordsServiceImpl leaveApprovalRecordsServiceImpl;
    @Autowired
    private ReplaceCardApprovalRecordsServiceImpl replaceCardApprovalRecordsServiceImpl;
    @Autowired
    private OvertimeApprovalRecordsServiceImpl overtimeApprovalRecordsServiceImpl;
    @Autowired
    private ExtraServiceImpl extraServiceImpl;
    @Autowired
    private DictServiceImpl dictServiceImpl;

    /**
     * 缴存基数
     * 
     * @param page
     * @param query
     * @return
     */
    @GetMapping("/deposit/base")
    public R<IPage<Salary>> depositBase(Page<Salary> page, CommonQuery query) {
        return this.success(this.salaryServiceImpl.depositBase(page, query));
    }

    /**
     * 工资分布
     * 
     * @return
     */
    @GetMapping
    public R<List<Map<String, String>>> wageDistribution() {
        return this.salaryServiceImpl.wageDistribution();
    }

    /**
     * 查看个人
     * 
     * id是userId
     * 
     * @return
     */
    @GetMapping("/info")
    public R<Salary> getById(String id) {

        Salary salary = this.salaryServiceImpl.getOne(new QueryWrapper<Salary>().eq("user_id", id));

        if (salary == null) {
            return this.failed("该用户没有对应的薪资信息，请完善");
        }

        InsuranceRate rate = this.insuranceRateServiceImpl.list().get(0); // 保险费率有且仅有一条
        salary.setYanglao(this.salaryServiceImpl.multiply(salary.getWxjishu(), rate.getYanglao()));
        salary.setShiye(this.salaryServiceImpl.multiply(salary.getWxjishu(), rate.getShiye()));
        salary.setYiliao(this.salaryServiceImpl.multiply(salary.getWxjishu(), rate.getYiliao()));
        salary.setGongshang(rate.getGongshang());
        salary.setShengyu(rate.getShengyu());

        UserDept one = this.userDeptServiceImpl.getOne(new QueryWrapper<UserDept>().eq("user_id", id));
        Dept byId = this.deptServiceImpl.getById(one.getDeptId());
        salary.setDeptId(byId.getId());
        salary.setDeptName(byId.getName());

        User user = this.userServiceImpl.getById(id);

        salary.setUserName(user.getName());

        return this.success(salary);
    }

    /**
     * 工资明细
     * 
     * @param page
     * @param query
     * @return
     */
    @GetMapping("/record")
    public R<Map<String, Object>> salaryRecord(Page<SalaryVO> page, CommonQuery query, boolean insurance) {
        query.setEnd(DateUtil.getNextMonth(query.getStart()) + "-01");
        query.setStart(query.getStart() + "-01");

        if (query.getDeptId() == null) {
            query.setDeptId(query.getProjectId());
        }

        return this.success(this.salaryServiceImpl.salaryRecord(page, query, insurance));
    }

    @PutMapping
    public R<Boolean> save(@RequestBody Salary salary) {

        return this.success(
            this.salaryServiceImpl.update(salary, new UpdateWrapper<Salary>().eq("user_id", salary.getUserId())));
    }

    /**
     * 工资提交总部审批
     * 
     * @param projectId 项目的id
     * @param yearMonth
     * @return
     */
    @GetMapping("/submit")
    @Transactional
    public R<Boolean> salarySubmit(int projectId, String yearMonth) {
        /*
         * 查询部门是否有未审批的申请 ，即审批状态为0的，则不能提交财务审批
         * 
         * 提交财务审批，更新提交状态，提交时间 
         */
        CommonQuery query = new CommonQuery();
        query.setDeptId(projectId);
        query.setStart(yearMonth + "-01");
        query.setEnd(DateUtil.getNextMonth(yearMonth) + "-01");

        if (this.leaveApprovalRecordsServiceImpl.countApprove(query) > 0) {
            return this.failed("该部门有请假申请未审批，请审批后重试");
        }

        if (this.overtimeApprovalRecordsServiceImpl.countApprove(query) > 0) {
            return this.failed("该部门有加班申请未审批，请审批后重试");
        }

        if (this.replaceCardApprovalRecordsServiceImpl.countApprove(query) > 0) {
            return this.failed("该部门有补卡申请未审批，请审批后重试");
        }
        /*
         * 根据项目获取项目部下所有的部门人员
         * 查询工资记录
         * 结转操作，
         * 修改当月状态，
         * 删除下月记录
         * 插入下月记录
         * TODO 加入汇总（参照工资明细的总工资）的数据存入到表中（待设计），供查询曲线分析
         */
        List<Integer> deptIds =
            this.deptServiceImpl.list(new QueryWrapper<Dept>().eq("parent_id", projectId).or().eq("id", projectId))
                .stream().map(d -> d.getId()).collect(Collectors.toList());

        List<SalaryRecord> recordList = this.salaryRecordServiceImpl
            .list(new QueryWrapper<SalaryRecord>().in("dept_id", deptIds).eq("date", yearMonth));

        Multimap<Integer, SalaryRecord> multiMap = ArrayListMultimap.create();

        for (SalaryRecord record : recordList) {
            User user = this.userServiceImpl.getById(record.getUserId());

            if (user == null || !user.isValid()) {
                continue;
            }

            record.setSubmit(true);
            record.setSubmitTime(LocalDateTime.now());
            record.setGrantable(true);
            record.setGrantTime(LocalDateTime.now());

            record.setExtra(this.extraServiceImpl.countUserExtra(query));
            BigDecimal qingjia =
                this.salaryServiceImpl.calcLeaveFee(record.getUserId(), query.getStart(), query.getEnd());
            record.setQingjia(qingjia.toString());
            BigDecimal jiaban =
                this.salaryServiceImpl.calcOvertimeFee(record.getUserId(), query.getStart(), query.getEnd());
            record.setJiaban(jiaban.toString());

            query.setUserId(record.getUserId());
            Map<String, BigDecimal> chidaoZaotui = this.salaryServiceImpl.chidaoZaotui(query);
            record.setChidao(chidaoZaotui.get("lateMoney").toString());
            record.setZaotui(chidaoZaotui.get("earlyMoney").toString());

            multiMap.put(record.getDeptId(), record);

            this.salaryRecordServiceImpl.updateById(record);

            this.salaryRecordServiceImpl.remove(new QueryWrapper<SalaryRecord>()
                .eq("date", DateUtil.getNextMonth(yearMonth)).eq("user_id", record.getUserId()));

            record.setId(null);
            record.setSubmit(null);
            record.setSubmitTime(null);
            record.setGrantable(null);
            record.setGrantTime(null);
            record.setDate(DateUtil.getNextMonth(yearMonth));

            record.setChidao("0");
            record.setZaotui("0");
            record.setQingjia("0");
            record.setExtra("0");
            record.setJiaban("0");
            this.salaryRecordServiceImpl.save(record);
        }

        for (Integer deptId : multiMap.keySet()) {
            Collection<SalaryRecord> deptRecord = multiMap.get(deptId);

            DeptCollect dc = new DeptCollect();

            dc.setDeptId(deptId);
            dc.setCreateTime(DateUtil.getNormalTime());
            dc.setCycle(yearMonth);

            BigDecimal unInsuranceTotal = BigDecimal.valueOf(0);
            BigDecimal insuranceTotal = BigDecimal.valueOf(0);
            int insurancePeople = 0, unInsurancePeople = 0;

            for (SalaryRecord sr : deptRecord) {
                sr.setBaozhang(this.dictServiceImpl.getLabel("baozhang", sr.getBaozhang()));

                BigDecimal personalTotal = new BigDecimal(sr.getGangwei()).add(new BigDecimal(sr.getBaozhang()))
                    .add(new BigDecimal(sr.getGongling())).add(new BigDecimal(sr.getJiaban()))
                    .add(new BigDecimal(Optional.ofNullable(sr.getExtra()).orElse("0")))
                    .subtract(new BigDecimal(sr.getQingjia()).add(new BigDecimal(sr.getChidao()))
                        .add(new BigDecimal(sr.getZaotui())));

                boolean insurance = this.userServiceImpl.getById(sr.getUserId()).isInsurance();

                if (insurance) {
                    insuranceTotal = insuranceTotal.add(personalTotal);
                    insurancePeople++;
                } else {
                    unInsuranceTotal = unInsuranceTotal.add(personalTotal);
                    unInsurancePeople++;
                }
            }

            dc.delete(new QueryWrapper<DeptCollect>().eq("dept_id", deptId).eq("cycle", yearMonth));
            dc.setSalary(insuranceTotal.toString());
            dc.setPeopleNum(insurancePeople);
            dc.setInsurance(true);
            dc.insert(); // 部门缴纳保险的人数汇总

            dc.setInsurance(false);
            dc.setSalary(unInsuranceTotal.toString());
            dc.setPeopleNum(unInsurancePeople);
            dc.insert(); // 部门不缴纳保险的人数汇总
        }

        return this.success(true);
    }

    @GetMapping("/export")
    public void exportSalary(HttpServletResponse response, CommonQuery query, boolean insurance) {
        query.setEnd(DateUtil.getNextMonth(query.getStart()) + "-01");
        query.setStart(query.getStart() + "-01");

        if (query.getDeptId() == null) {
            query.setDeptId(query.getProjectId());
        }
        this.salaryServiceImpl.exportSalary(response, query, insurance);
    }
}
